package tarantula.collector;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import tarantula.instrumenter.SourcePos;
import tarantula.instrumenter.SourcePosExecInfo;
import tarantula.instrumenter.Tracer;
import tarantula.util.FileUtils;
import tarantula.util.Globals;

public class TestDataCollector {
	
	public static boolean DUMP_COLLECTED_RESULT = false;
	
	enum EXEC_RESULT {PASS, FAIL};
	
	public final Map<File, EXEC_RESULT> testDataFiles = new LinkedHashMap<File, EXEC_RESULT>();
	
	public final int total_passing_test_num;
	public final int total_failing_test_num;
	
	public TestDataCollector(String dir) {
		int pass_num = 0;
		int fail_num = 0;
		
		for(File file : FileUtils.findFilesInDirRecur(new File(dir))) {
			if(file.getName().endsWith(Tracer.trace_file_suffix)) {
				//check the validity of each file
				if(Tracer.checkFileValidity(file)) {
				   if(Tracer.isPassingTestFile(file)) {
					   pass_num ++;
					   testDataFiles.put(file, EXEC_RESULT.PASS);
				   } else {
					   fail_num ++;
					   testDataFiles.put(file, EXEC_RESULT.FAIL);
				   }
				} else {
					throw new RuntimeException("The file: " + file.getAbsolutePath()
							+ " is not valid");
				}
			}
		}
		
		total_passing_test_num = pass_num;
		total_failing_test_num = fail_num;
	}
	
	
	public Map<SourcePos, ExecResults> collectTestDataInfo() {
		
		Map<SourcePos, ExecResults> testDataInfo = new LinkedHashMap<SourcePos, ExecResults>();
		
		for(File file : testDataFiles.keySet()) {
			EXEC_RESULT result = testDataFiles.get(file);
			
			List<SourcePosExecInfo> sourcePosExec = Tracer.parse(file.getAbsolutePath());
			for(SourcePosExecInfo execInfo : sourcePosExec) {
				SourcePos sourcePos = execInfo.pos;
				
				if(!testDataInfo.containsKey(sourcePos)) {
					ExecResults newResult = new ExecResults(total_failing_test_num, total_passing_test_num);
					if(result == EXEC_RESULT.FAIL) {
						newResult.incrFailingTestNum();
					} else if (result == EXEC_RESULT.PASS) {
						newResult.incrPassingTestNum();
					} else {
						throw new Error();
					}
					testDataInfo.put(sourcePos, newResult);
				} else {
					if(result == EXEC_RESULT.FAIL) {
						testDataInfo.get(sourcePos).incrFailingTestNum();
					} else if (result == EXEC_RESULT.PASS) {
						testDataInfo.get(sourcePos).incrPassingTestNum();
					} else {
						throw new Error();
					}
				}
			}
		}
		
		//check the correctness here
		if(DUMP_COLLECTED_RESULT) {
			dumpCollectResult(testDataInfo);
		}
		checkResults(testDataInfo);
		
		return testDataInfo;
	}
	
	private void checkResults(Map<SourcePos, ExecResults> execdata) {
		for(SourcePos pos : execdata.keySet()) {
			ExecResults result = execdata.get(pos);
			if( result.passing_test_num == 0 && result.failing_test_num == 0) {
				throw new RuntimeException("For source position: " + pos.toString() + ", there is no test covered, why recorded?");
			}
		}
	}
	
	public static void dumpCollectResult(Map<SourcePos, ExecResults> execdata) {
		for(SourcePos pos : execdata.keySet()) {
			ExecResults result = execdata.get(pos);
			System.out.println("   pos: " + pos + ",   results: " + result);
			//System.out.println(Globals.lineSep);
		}
	}
	
}